/**
 * System:      oshys
 * Model:       common
 * Licence:     GNU General Public License v3
 * Author:      qingkang
 * Date:        2010/03/28
 */
package org.oshys.util.resource;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

/**
 * 此类用于国际化消息.
 * <p>
 * 说明
 * <ul>
 * <li>根据给定包名，读取包下的LocalStrings_${locale}.properties文件完成资源文件的加载.
 * <li>之后调用该类的方法获得相应消息.
 * </ul>
 * <p>
 * 使用实例(通常，一个包名对应一个LocalStringsManager)
 * <p>
 * 背景:
 * <ul>
 * <li>包名:a.b.c
 * <li>资源文件:以上包下新建一个LocalStrings_${locale}.properties文件,最好也新建一个默认LocalStrings.properties.
 * <li>如果消息体中需要使用动态参数，则用{0},{1}...{n}等，用大括号里包含顺序号.
 * <li>资源文件内容举例: a=this is test message a;b=this is test message,value is:{0}.
 * </ul>
 * <p>
 * 使用方法:
 * <li>LocalStringsManager lsm = LocalStringsManager.getManager(a.b.c);
 * <li>lsm.getString(a);//获得this is test message a.
 * <li>lsm.getString(a,"test.value");//获得this is test message,value
 * is:test.value.
 */
public class LocalStringsManager {
	/**
	 * 国际化辅助，真正实现国际化的核心.
	 */
	private ResourceBundle bundle;

	/**
	 * 从效率考虑，用Map存储目前所有LocalStringsManager,如果给定包名已经存在，那么就直接从Map中获取.
	 */
	private static HashMap<String, LocalStringsManager> cache = new HashMap<String, LocalStringsManager>();

	private static String propertiesFilename = "LocalStrings";

	/**
	 * 根据包名取得LocalStringsManager.
	 * 
	 * @param packageName
	 *            包名.
	 * @return LocalStringsManager.
	 */
	public static LocalStringsManager getManager(String packageName) {
		// Fristly,get LocalStringsManager from cache.
		if (cache.containsKey(packageName)) {
			return cache.get(packageName);
		}

		LocalStringsManager newOne = new LocalStringsManager(packageName);
		cache.put(packageName, newOne);
		return newOne;
	}

	/**
	 * 
	 * 根据类取得LocalStringsManager.
	 * 
	 * @param clazz
	 *            类.
	 * @return LocalStringsManager.
	 */
	public static LocalStringsManager getManager(Class clazz) {
		String packageName = getPackageName(clazz);
		return getManager(packageName);
	}

	/**
	 * 从指定的包名生成一个LocalStringsManager.
	 * 
	 * @param packageName
	 *            包名
	 */
	private LocalStringsManager(String packageName) {
		setBundle(packageName);
	}

	/**
	 * 根据指定的class生成一个LocalStringsManager.
	 * 
	 * @param clazz
	 *            类
	 */
	private LocalStringsManager(Class clazz) {
		String packageName = getPackageName(clazz);
		setBundle(packageName);
	}

	/**
	 * 通过key值获得本地化消息.
	 * 
	 * @param key
	 *            资源文件中定义的key
	 *@return 资源文件中定义的消息
	 */
	public String get(String key, Object... objects) {
		String indexString = get(key);
		try {
			MessageFormat mf = new MessageFormat(indexString);
			return mf.format(objects);
		} catch (Exception e) {
			return indexString;
		}
	}

	/**
	 * 通过key值获得本地化消息.
	 * 
	 * @param key
	 *            资源文件中定义的key
	 *@return 资源文件中定义的消息
	 */
	protected String get(String key) {
		if (null == key) {
			return "Please note that:This message Cannot be seen by user, key is null,should specify the key for get the i18n message.";
		}

		String localMessage = null;
		if (bundle == null) {
			return key;
		}

		try {
			localMessage = bundle.getString(key);
		} catch (MissingResourceException mre) {
			return key;
		}

		return localMessage;
	}

	/**
	 * 根据packageName设置ResourceBundle
	 * 
	 * @param packageName 包名
	 */
	private void setBundle(String packageName) {
		String props = null;
		if (null == packageName) {
			props = "" + propertiesFilename;
		}

		try {
			props = packageName + '.' + propertiesFilename;
			bundle = ResourceBundle.getBundle(props);
		} catch (Exception e) {
			bundle = null;
		}
	}

	/**
	 * 根据Class取得包名.
	 * @param clazz 类
	 */
	private static String getPackageName(Class clazz) {
		String className = clazz.getName();
		// handle the default package...
		if (className.indexOf('.') < 0) {
			return "";
		} else {
			return className.substring(0, className.lastIndexOf('.'));
		}
	}
}
